#include <common.h>
#include "syscall.h"
#include <fs.h>
#include <sys/time.h>
#include <proc.h>
extern void naive_uload(PCB *pcb, const char *filename);
extern size_t ramdisk_read(void *buf, size_t offset, size_t len);
extern size_t ramdisk_write(const void *buf, size_t offset, size_t len);
int sys_yield(){
  yield();
  return 0;
}

int sys_exit(int code){
  naive_uload(NULL, "/bin/nterm");
  // printf("The exit code is %d\n",code);
  // halt(code);
  return 0;
}

int sys_write(int fd, void *buf, size_t count){
  int ret = fs_write(fd, buf, count);
  return ret;
}

int sys_brk(__intptr_t addr){
  return 0;
}

int sys_open(const char *path, int flags, int mode){
  int ret = fs_open(path, flags, mode);
  return ret;
}

int sys_read(int fd, void *buf, size_t count){
  int ret = fs_read(fd, buf, count);
  return ret;
}
size_t sys_lseek(int fd, size_t offset, int whence){
  size_t ret = fs_lseek(fd, offset, whence);
  return ret;
}

int sys_close(int fd){
  int ret = fs_close(fd);
  return ret;
}
int sys_gettimeofday(struct timeval *tv, struct timezone *tz){
  uint64_t us = io_read(AM_TIMER_UPTIME).us;
  
  if(tv != NULL){
    tv->tv_sec = us / 1000000;
    tv->tv_usec = us % 1000000;
  }

  return 0;
}
int sys_execve(const char *fname, char * const argv[], char *const envp[]){
  printf("execve file: %s\n",fname);
  naive_uload(NULL, fname);
  assert(0);
  return 0;
}
void do_syscall(Context *c) {
  uintptr_t a[4];
  a[0] = c->GPR1; // a7
  a[1] = c->GPR2; // a0
  a[2] = c->GPR3; // a1
  a[3] = c->GPR4; // a2
  // Log("syscall %d call ",a[0]);
  switch (a[0]) {
    case SYS_exit:            c->GPRx = sys_exit(a[1]);                         break;
    case SYS_yield:           c->GPRx = sys_yield();                            break;
    case SYS_open:            c->GPRx = sys_open((char*)a[1], a[2], a[3]);      break;
    case SYS_close:           c->GPRx = sys_close(a[1]);                        break;
    case SYS_write:           c->GPRx = sys_write(a[1], (void *)a[2], a[3]);    break;
    case SYS_read:            c->GPRx = sys_read(a[1], (void *)a[2], a[3]);     break;
    case SYS_lseek:           c->GPRx = sys_lseek(a[1], a[2], a[3]);            break;
    case SYS_gettimeofday:    c->GPRx = sys_gettimeofday((void *)a[1],(void *)a[2]);            break;
    case SYS_execve:          c->GPRx = sys_execve((void *)a[1], (void *)a[2], (void *)a[3]);   break;
    case SYS_brk:             c->GPRx = sys_brk(a[1]);                          break;
    default: panic("Unhandled syscall ID = %d", a[0]);
  }
}
